package com.liy.framework.common.tree;

import com.liy.framework.common.utils.ReflectUtil;

import java.util.*;

public class TreeUtil<T>
{
    private List<TreeNode> treeNodeList;
    private List<T> data;
    private String rootValue;
    private List<TreeNode> tempData;
    private List<TreeNode> nodeData;
    private TreeNodeMapping mapping;

    public TreeUtil(final List<T> data, final String rootValue) {
        this.treeNodeList = new ArrayList<TreeNode>();
        this.rootValue = "0";
        this.tempData = null;
        this.nodeData = null;
        this.data = data;
        this.rootValue = rootValue;
        this.mapping = new TreeNodeMapping();
    }

    public TreeUtil(final List<T> data, final String rootValue, final TreeNodeMapping mapping) {
        this.treeNodeList = new ArrayList<TreeNode>();
        this.rootValue = "0";
        this.tempData = null;
        this.nodeData = null;
        this.data = data;
        this.rootValue = rootValue;
        this.mapping = ((mapping != null) ? mapping : new TreeNodeMapping());
    }

    public List<TreeNode> processToList() {
        if (this.data == null && this.data.size() <= 0) {
            return this.treeNodeList;
        }
        final List<TreeNode> rootNode = this.findRootList(this.rootValue);
        this.nodeData.removeAll(rootNode);
        for (final TreeNode node : rootNode) {
            this.tempData = new ArrayList<TreeNode>();
            this.eachRootNode(node, this.nodeData);
            this.nodeData.removeAll(this.tempData);
            this.treeNodeList.add(node);
        }
        return this.treeNodeList;
    }

    public TreeNode processToOneNode(final String name) {
        final List<TreeNode> list = this.processToList();
        final TreeNode node = new TreeNode();
        node.setId("");
        node.setPid("");
        node.setName(name);
        node.setIcon("");
        node.setChildren(list);
        return node;
    }

    private List<TreeNode> findRootList(final String rootValue) {
        final List<TreeNode> rootList = new ArrayList<TreeNode>();
        this.nodeData = new ArrayList<TreeNode>();
        for (final T t : this.data) {
            final TreeNode node = this.getTreeNode(t);
            if (rootValue.equals(node.getPid())) {
                rootList.add(node);
            }
            this.nodeData.add(node);
        }
        return rootList;
    }

    private void eachRootNode(final TreeNode parentNode, final List<TreeNode> itemList) {
        final List<TreeNode> childrenList = new ArrayList<TreeNode>();
        for (final TreeNode node : itemList) {
            if (parentNode.getId().equals(node.getPid())) {
                this.tempData.add(node);
                this.eachRootNode(node, itemList);
                childrenList.add(node);
            }
        }
        parentNode.setChildren(childrenList);
    }

    private TreeNode getTreeNode(final T t) {
        final String id = (String) ReflectUtil.getFieldValue(this.mapping.getId(), t);
        final String pid = (String)ReflectUtil.getFieldValue(this.mapping.getPid(), t);
        final String name = (String)ReflectUtil.getFieldValue(this.mapping.getName(), t);
        final String icon = (String)ReflectUtil.getFieldValue(this.mapping.getIcon(), t);
        final TreeNode node = new TreeNode();
        node.setId(id);
        node.setPid(pid);
        node.setName(name);
        node.setIcon(icon);
        if (this.mapping.getAttributes() != null) {
            final Map<String, Object> attributeMap = new HashMap<String, Object>();
            for (final String key : this.mapping.getAttributes()) {
                final Object val = ReflectUtil.getFieldValue(key, t);
                attributeMap.put(key, val);
            }
            node.setAttributes(attributeMap);
        }
        return node;
    }
}
